package empty.dsa.generator

import chisel3._
import chisel3.util._
import empty.dsa.util.OpInfo
// DPM生成器
// 输入参数：
//   1. 元素名称
//   2. 操作类型
//   3. 输入数量
//   4. 数据集数量
//   5. PE数量
//   6. 循环次数
//   7. 宽度
class DPM(elename: String, op_type: Int, in_num: Int, data_sets: Int, PE_num: Int, cycle : Int, width: Int) extends Module{
  //一个周期输入十六个数据（先不考虑数据扩展）
  override val desiredName = elename
  println("DPM :" + op_type)
  val alu_type = OpInfo.fuget(op_type)
  println("alu_type : " + alu_type)
  val max_cycle = alu_type.map(OpInfo.getOperandCycle(_)).max
  val max_out = alu_type.map(OpInfo.getDPMoutNum(_)).max
  println("max_out :" + max_out)
  val out_num = max_out * PE_num
  //先考虑只有一个输出的情况
  val io = IO(new Bundle() {
    //cfg分高低控制为，低两位0~1控制数据输入输出，高几位控制运算类型
    val cfg = Input(UInt(7.W)) //cfg = 1时开始读入数据，cfg = 2时开始往外输出数据，cfg同时需要确定运算类型，从而确定outbuffers的数据
    val inputs = Input(Vec(in_num, UInt(width.W)))
    val outputs = Output(Vec(PE_num, UInt(width.W)))
    //val outputs = Output(Vec(PE_num * 2, UInt(width.W)))  //sha1两级合在一起
  })
  val data_in_wire = Wire(UInt(log2Ceil(data_sets).W))
  val data_in_Reg = RegEnable(data_in_wire + 1.U, 0.U, data_in_wire < data_sets.U)
  data_in_wire := data_in_Reg
  val inbuffers = RegInit(VecInit(Seq.fill(data_sets)(VecInit(Seq.fill(in_num)(0.U(width.W)))))) // 创建多个输入缓冲区，每个缓冲区存放in_num个数据
  when(io.cfg(0) === 1.U) {
    inbuffers(data_in_wire) := io.inputs
  }
  //创建一个输出计数寄存器
  val data_out_wire = Wire(UInt(10.W))
  val data_out_reg = RegEnable(data_out_wire + 1.U, 0.U, io.cfg(1) === 1.U)
  data_out_wire := data_out_reg

  //循环选择数据输出的来源
  val cntwire = Wire(UInt(log2Ceil(PE_num).W))
  val cntReg = RegEnable(cntwire + 1.U, 0.U, io.cfg(1) === 1.U)
  cntwire := cntReg

  val oreder = List(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
    1, 6, 11, 0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12,
    5, 8, 11, 14, 1, 4, 7, 10, 13, 0, 3, 6, 9, 12, 15, 2,
    0, 7, 14, 5, 12, 3, 10, 1, 8, 15, 6, 13, 4, 11, 2, 9)


  val DPM1_module = Seq.tabulate(PE_num)(i => Module(new DMP1(1,32, PE_num, i + 1, oreder(i % 64))))

  DPM1_module(0).io.inputs := io.inputs
  DPM1_module(0).io.cfg := io.cfg
  for(i <- 1 until PE_num) {
    for(j <- 0 until 16){
      DPM1_module(i).io.inputs(j) := DPM1_module(i - 1).io.outputs(j + 1)
    }
    DPM1_module(i).io.cfg := io.cfg
  }
  for(i <- 0 until PE_num) {
    io.outputs(i) := DPM1_module(i).io.outputs(0)
  }

}

// 定义DMP1生成器
class DMP1(op_type: Int, width: Int, PE_num: Int, NO_PE: Int, md5_NO: Int) extends Module {
  val io = IO(new Bundle() {
    val inputs = Input(Vec(16, UInt(width.W)))  //最后一位作为计数器，前16位作为数据输入
    val cfg = Input(UInt(7.W))
    //val counter = Input(UInt(10.W))
    val outputs = Output(Vec(17, UInt(width.W)))
    //val outputs = Output(Vec(18, UInt(width.W)))  //两级运算合在一起，增加一个输出
  })
  val inputsWire = Wire(Vec(16, UInt(width.W)))
  for(i <- 0 until 16) {
    inputsWire(i) := RegNext(io.inputs(i))
  }
  val alu_type = OpInfo.fuget(op_type)

  //只有md5

    io.outputs(0) := io.inputs(md5_NO)
    for(i <- 1 until 17) {
      io.outputs(i) := inputsWire(i - 1)
    }

}
